from PyQt5.QtCore import QThread
import base,message
import socket,time
import struct

class MyThread(QThread):
    def __init__(self,func,args):
        super(MyThread,self).__init__()
        self.func = func
        self.args = args
    def run(self):
        self.func(self.args)

class clientso(QThread,message.msg):
    CON_UP = 1
    CON_DOWN = 2

    def __init__(self,updfunc,upcfunc,ser_address,thr_event):
        super(clientso, self).__init__()
        self.__so = socket.socket()
        self.__ser_address =(ser_address)
        self.__sendtoupperf = updfunc #通知上层数据接口
        self.__contoupperf  = upcfunc #通知上层控制接口,这里为连接down/UP
        self.__thr_event = thr_event
        self._setlogName('ClientSo')

    def setserver(self,ser_address):
        self.__ser_address = ser_address

    def sendtoserver(self,send_bytes):
        try:
            l = len(send_bytes) + struct.calcsize('i')
            send_bytes = bytes().join([struct.pack('!i',l),send_bytes])
            self._log('send:%s'%send_bytes,self.LOG_DEBUG)
            self.__so.sendall(send_bytes)
            return 0
        except socket.error as e:
            self._log(str(e),self.LOG_DEBUG)
            return -1
            #重启线程connect
            #这里socket断开异常应该先被recv 线程察觉，不需要再起线程connect了
            #reconn_thr = MyThread(self.__connect,None)
            #reconn_thr.start()
            #self._log('send failed, connect is down', self.LOG_DEBUG)
            #raise e  #特别注意，抛出的异常如果没有处理，最终会上层程序捕获停止

    def __connect(self):
        isconnect = False
        while not isconnect:
            try:
                self.__so.connect(self.__ser_address)
                isconnect = True
                self._log('conected.')
            except socket.error as e:
                # 如果是输入不合法，则立即返回,或抛出异常
                # return
                # 如果是服务器连接异常，则休眠1s继续尝试连接
                self._log('connect failed,reason:%s'%str(e),self.LOG_DEBUG)
                time.sleep(1)
                continue

    def run(self):
        self.__connect()
        self.__contoupperf(self.CON_UP)
        left_bytes = bytes()
        while True:
            try:
                recv_bytes = self.__so.recv(1024)
                self._log('recv:%s'%recv_bytes,self.LOG_DEBUG)

                left_bytes = bytes().join([left_bytes,recv_bytes])

                while len(left_bytes) > 4:
                    l, = struct.unpack('!i',left_bytes[:4])
                    if l > len(left_bytes):
                        break
                    self.__sendtoupperf(left_bytes[4:l],self.__thr_event)
                    left_bytes = left_bytes[l:]

            except socket.error as e:
                self._log(str(e))
                #如果异常说明，连接断了，则重新连接
                #先关闭本端socket，而后重新创建
                #*******************此处要加锁，避免修改过程中,__so被抢占调用发送
                self.__so.close()
                self.__so = socket.socket()
                self._log('so recreated',self.LOG_DEBUG)

                #这里要通知上层链接断开
                self.__contoupperf(self.CON_DOWN)
                self.__connect()
                self.__contoupperf(self.CON_UP)
                continue




